/**
 * DEM数据读取器类
 * 用于读取ASCII格式的DEM数据文件并进行高程计算
 */
class DemReader {
    constructor() {
        this.ncols = 0;
        this.nrows = 0;
        this.xllcorner = 0.0; // 左下角经度
        this.yllcorner = 0.0; // 左下角纬度
        this.cellsize = 0.0;
        this.demData = [];
        this.dataLoaded = false;
        this.NODATA_VALUE = -9999.0;
    }

    /**
     * 加载DEM数据文件
     * @param {string} filePath - DEM文件路径
     * @returns {Promise<boolean>} - 加载是否成功
     */
    async loadDemData(filePath) {
        try {
            const response = await fetch(filePath);
            const text = await response.text();
            const lines = text.split('\n');
            
            this.demData = [];
            this.dataLoaded = false;
            let dataStartIndex = 0;
            
            // 解析头部信息
            for (let i = 0; i < lines.length; i++) {
                const line = lines[i].trim();
                if (line === '') continue;
                
                const parts = line.split(/\s+/);
                const keyword = parts[0];
                
                if (keyword === 'ncols') {
                    this.ncols = parseInt(parts[1]);
                } else if (keyword === 'nrows') {
                    this.nrows = parseInt(parts[1]);
                } else if (keyword === 'xllcorner') {
                    this.xllcorner = parseFloat(parts[1]);
                } else if (keyword === 'yllcorner') {
                    this.yllcorner = parseFloat(parts[1]);
                } else if (keyword === 'cellsize') {
                    this.cellsize = parseFloat(parts[1]);
                } else if (keyword === 'NODATA_value') {
                    // 这里我们知道NODATA_value是'x'
                    // 继续处理
                } else {
                    // 找到数据开始的行
                    dataStartIndex = i;
                    break;
                }
            }
            
            // 加载高程数据
            console.warn(`警告: DEM数据非常大 (${this.ncols}x${this.nrows}), 尝试使用更高效的加载方式...`);
            
            for (let i = dataStartIndex; i < lines.length; i++) {
                const line = lines[i].trim();
                if (line === '') continue;
                
                const parts = line.split(/\s+/);
                const rowData = [];
                
                for (let j = 0; j < parts.length; j++) {
                    if (parts[j] === 'x') {
                        rowData.push(this.NODATA_VALUE);
                    } else {
                        try {
                            rowData.push(parseFloat(parts[j]));
                        } catch (e) {
                            console.error(`解析DEM数据时出错，行: ${i}, 值: ${parts[j]}, 设为无效值`);
                            rowData.push(this.NODATA_VALUE);
                        }
                    }
                }
                
                // 检查数据点数量是否符合预期
                if (rowData.length !== this.ncols) {
                    console.warn(`警告: 第${i}行的数据点数量 (${rowData.length}) 与预期不同 (${this.ncols}), 尝试继续...`);
                    
                    // 如果数据点不足，填充NODATA_VALUE
                    if (rowData.length < this.ncols) {
                        while (rowData.length < this.ncols) {
                            rowData.push(this.NODATA_VALUE);
                        }
                    }
                }
                
                this.demData.push(rowData);
                
                // 每100行显示一次进度
                if (i % 100 === 0) {
                    console.log(`已加载${i - dataStartIndex}行数据...`);
                }
            }
            
            this.dataLoaded = true;
            console.log(`成功加载DEM数据: ${this.ncols}x${this.nrows} 网格，左下角坐标(${this.xllcorner}, ${this.yllcorner})，单元格大小: ${this.cellsize}`);
            return true;
        } catch (error) {
            console.error(`无法加载DEM数据文件: ${error.message}`);
            return false;
        }
    }

    /**
     * 将经纬度转换为网格坐标
     * @param {number} longitude - 经度
     * @param {number} latitude - 纬度
     * @returns {object|null} - 包含col和row的对象，如果坐标不在范围内则返回null
     */
    latLonToGrid(longitude, latitude) {
        // 计算列号和行号
        // 列号 = (经度 - 左下角经度) / 单元格大小
        const col = Math.floor((longitude - this.xllcorner) / this.cellsize);
        // 行号 = (左下角纬度 + 行数*单元格大小 - 纬度) / 单元格大小
        // 注意这里行号的计算是倒序的，因为DEM数据通常从上到下存储
        const row = Math.floor((this.yllcorner + this.nrows * this.cellsize - latitude) / this.cellsize);
        
        // 检查坐标是否在数据范围内
        // 注意需要-1，因为我们需要至少两个点进行双线性插值
        if (col < 0 || col >= this.ncols - 1 || row < 0 || row >= this.nrows - 1) {
            console.error(`坐标(${longitude}, ${latitude}) 不在DEM数据范围内`);
            return null;
        }
        
        return { col, row };
    }

    /**
     * 使用双线性插值计算给定坐标的高程值
     * @param {number} longitude - 经度
     * @param {number} latitude - 纬度
     * @returns {number} - 计算得到的高程值
     */
    bilinearInterpolation(longitude, latitude) {
        const gridPos = this.latLonToGrid(longitude, latitude);
        if (!gridPos) {
            return 0.0;
        }
        
        const { col, row } = gridPos;
        
        // 计算在单元格中的相对位置
        // xRatio和yRatio表示目标点在网格单元内的相对坐标(0-1之间)
        const xRatio = (longitude - (this.xllcorner + col * this.cellsize)) / this.cellsize;
        const yRatio = (latitude - (this.yllcorner + (this.nrows - row - 1) * this.cellsize)) / this.cellsize;
        
        // 获取四个角点的高程值
        // z1: 左下角, z2: 右下角, z3: 左上角, z4: 右上角
        const z1 = this.demData[row][col];
        const z2 = this.demData[row][col + 1];
        const z3 = this.demData[row + 1][col];
        const z4 = this.demData[row + 1][col + 1];
        
        // 检查是否有无效数据点
        let validPoints = 0;
        let sumZ = 0.0;
        
        if (z1 !== this.NODATA_VALUE) { validPoints++; sumZ += z1; }
        if (z2 !== this.NODATA_VALUE) { validPoints++; sumZ += z2; }
        if (z3 !== this.NODATA_VALUE) { validPoints++; sumZ += z3; }
        if (z4 !== this.NODATA_VALUE) { validPoints++; sumZ += z4; }
        
        // 如果所有点都是无效的，返回0
        if (validPoints === 0) {
            console.warn(`警告: 查询点周围没有有效高程数据`);
            return 0.0;
        }
        
        // 如果部分点无效，使用有效点的平均值
        if (validPoints < 4) {
            console.warn(`警告: 查询点周围部分数据无效，使用平均值`);
            return sumZ / validPoints;
        }
        
        // 双线性插值计算
        // 双线性插值的公式：
        // z = (1-x) * (1-y) * z1 + x*(1-y)*z2 + (1-x)*y*z3 + x*y*z4
        // 其中x和y是相对位置，z1-z4是四个角点的高程
        // 这个公式实际上是在两个方向上进行线性插值，先横向，再纵向
        const z = (1 - xRatio) * (1 - yRatio) * z1 + 
                  xRatio * (1 - yRatio) * z2 + 
                  (1 - xRatio) * yRatio * z3 + 
                  xRatio * yRatio * z4;
        
        return z;
    }

    /**
     * 计算给定经纬度的高程值
     * @param {number} longitude - 经度
     * @param {number} latitude - 纬度
     * @returns {number} - 高程值
     */
    calculateElevation(longitude, latitude) {
        if (!this.dataLoaded || this.demData.length === 0) {
            console.error(`DEM数据未加载`);
            return 0.0;
        }
        
        // 使用双线性插值计算高程
        return this.bilinearInterpolation(longitude, latitude);
    }
}